package nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

public class MyServer {
    private int size = 1024;
    private ServerSocketChannel serverSocketChannel;
    private ByteBuffer byteBuffer;
    private Selector selector;
    private int remoteClientNum = 0;

    public MyServer(int port) {
        try {
            initChannel(port);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }
    }

    private void initChannel(int port) throws IOException {
        //打开Channel
        serverSocketChannel = ServerSocketChannel.open();
        //设置为非阻塞
        serverSocketChannel.configureBlocking(false);
        //绑定端口
        serverSocketChannel.bind(new InetSocketAddress(port));
        System.out.println("监听端口："+port);
        //选择器的创建
        selector = Selector.open();
        //向选择器注册通道
        serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
        //分配缓存区的大小
        byteBuffer= ByteBuffer.allocate(size);
    }

    //监听器，用于监听Channel上的数据变化
    private void listener() throws IOException {
        while (true){
            //返回int值表示有多少个Channel处于就绪
            int select = selector.select();
            System.out.println("当前有"+select+"个Channel处于就绪");
            if (select==0){
                continue;
            }
            //每个selector对应多个SelectionKey,每个SelectionKey对应一个Channel
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey next = iterator.next();
                //如果Selectionkey处于连接就绪状态，则开始接受客户端的连接
                if (next.isAcceptable()){
                    //获取Channel
                    ServerSocketChannel server = (ServerSocketChannel)next.channel();
                    //Channel接受连接
                    SocketChannel channel = server.accept();
                    //Channel注册
                    registerChannel(selector,channel,SelectionKey.OP_READ);
                    //远程客户端连接数
                    remoteClientNum++;
                    System.out.println("共有"+remoteClientNum+"个客户端连接");
                    write(channel,"hello 客户端".getBytes("UTF-8"));
                }
                //处于读就绪状态
                if (next.isReadable()){
                    read(next);
                }
                iterator.remove();
            }
        }
    }

    //读操作
    private void read(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel)key.channel();
        int count;
        byteBuffer.clear();
        //通道中读取数据到缓冲区
        while ((count = channel.read(byteBuffer)) > 0) {
            //byteBuffer变为读模式
            byteBuffer.flip();
            while (byteBuffer.hasRemaining()) {
                System.out.println((char)byteBuffer.get());
            }
            if ((count<0)) {
                channel.close();
            }
        }
    }

    //写操作
    private void write(SocketChannel channel,byte[] writeDate) throws IOException {
        byteBuffer.clear();
        byteBuffer.put(writeDate);
        //byteBuffer从写到读
        byteBuffer.flip();
        //将缓存区的数据写入通道中
        channel.write(byteBuffer);
    }

    //注册channel
    private void registerChannel(Selector selector,SocketChannel channel,int opRead) throws IOException {
        if (channel==null) {
            return;
        }
        channel.configureBlocking(false);
        channel.register(selector,opRead);
    }

    public static void main(String[] args) {
        MyServer myServer = new MyServer(9999);
        try {
            myServer.listener();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
